/* Copyright (C) 2021 Rain */

/* This file is part of XNIX. */

/* 
  XNIX is free software: you can redistribute it and/or modify 
  it under the terms of the GNU General Public License as published by 
  the Free Software Foundation, either version 3 of the License, or 
  (at your option) and later version. 
*/

/*
  XNIX is distributed in the hope that it will be useful, 
  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  GNU General Public License for more details. 
*/

/*
  You should have received a copy of the GNU General Public License 
   along with XNIX. If not, see <https://www.gnu.org/licenses/>.  
*/




#ifndef _PCI_H
#define _PCI_H

#include <kernel/types.h>
#include <kernel/errno.h>


__uint32_t pci_read_config(__uint8_t, __uint8_t, __uint8_t, __uint8_t);
__uint32_t pci_lspci(void);
void pci_infodev(__uint8_t, __uint8_t, __uint8_t);



/* the general pci header */

struct pci_header {
	__uint16_t vendor;
	__uint16_t dev;

	__uint16_t cmd;
	__uint16_t status;

	__uint8_t revision;
	__uint8_t prog_if;

	__uint8_t subclass;
	__uint8_t class_code;

	__uint8_t cache_size;
	__uint8_t latency;

	__uint8_t hdr_type;
	__uint8_t bist;
} __attribute__ ((packed));


/* regular device */

struct pci_header0 {
	struct pci_header hdr;

	__uint32_t bar0, bar1, bar2, 
		   bar3, bar4, bar5;

	/* a pointer that points to the info of the card (?) */
	__uint32_t cardbus_cis;
	__uint16_t subsys_vendor;
	__uint16_t subsys;

	/* extend rom base */
	__uint32_t erom_base;
	/* ? */
	__uint8_t capabilities;
	__uint16_t rsvd0;
	__uint8_t rsvd1;

	__uint32_t rsvd2;

	__uint8_t irqnr;

	/* it looks only for apic :-( */
	__uint8_t intpin;

	/* ? */
	__uint8_t min_grant;
	__uint8_t max_latency;
} __attribute__ ((packed));

/* pci-pci bridge */

struct pci_header1 {
	struct pci_header hdr;
	__uint32_t bar0, bar1;

	__uint8_t busnr_primary;
	__uint8_t busnr_secondary;
	__uint8_t busnr_sub;
	__uint8_t second_latency;

	__uint8_t io_base, io_limit;
	__uint16_t mem_limit;

	__uint16_t pre_mem_base;
	__uint16_t pre_mem_limit;

	/* for 48-bit long-mode */
	__uint32_t pre_base_high;
	__uint32_t pre_base_limit;

	__uint16_t io_high;
	__uint16_t io_limit_high;

	__uint8_t capabilities;
	__uint16_t rsvd0;
	__uint8_t rsvd1;

	__uint32_t erom_base;

	__uint8_t irqnr;
	__uint8_t intpin;

	__uint16_t bridge_ctl;
} __attribute__ ((packed));

/* pci-cardbus bridge */

struct pci_header2 {
	struct pci_header hdr;

	__uint32_t cardbus_base;

	__uint8_t caplist_offset;
	__uint8_t rsvd0;
	__uint16_t second_status;

	__uint8_t pcibus_nr;
	__uint8_t cardbus_nr;
	__uint8_t sub_bus_nr;
	__uint8_t latency;

	__uint32_t mmbase_0;
	__uint32_t mmlimit_0;

	__uint32_t mmbase_1;
	__uint32_t mmlimit_1;

	__uint32_t iobase_0;
	__uint32_t iolimit_0;

	__uint32_t iobase_1;
	__uint32_t iolimit_1;

	__uint8_t irqnr;
	__uint8_t intpin;

	__uint16_t bridge_ctl;

	__uint16_t subsys_dev;
	__uint16_t subsys_vendor;

	__uint32_t lagency_base;
} __attribute__ ((packed));

struct pci_device {
	__uint16_t devid;
	__uint16_t vendor;

	char *devname;

	/* the device configure word (256 bytes) */
	char *config;

	errno_t (* dev_init) (struct pci_header0 *);
};


struct pci_vendor_table {
	__uint8_t class;
	__uint8_t subclass;

	errno_t (* dev_init) (struct pci_header0 *);
};


/* pci_header.class-codes */

#define CLASS_UNK 	0x00
#define CLASS_DISK 	0x01
#define CLASS_NETCTL 	0x02
#define CLASS_DISPLAY 	0x03
#define CLASS_MEDIACTL 	0x04
#define CLASS_MMCTL 	0x05
#define CLASS_BRIDGE 	0x06
#define CLASS_CMMCTL 	0x07
#define CLASS_SYSDEV 	0x08
#define CLASS_INPUTDEV 	0x09
#define CLASS_DOCK 	0x0a
#define CLASS_CPU 	0x0b
#define CLASS_SBUS_CTL	0x0c
#define CLASS_WIRELESS 	0x0d
#define CLASS_INTCTL 	0x0e
#define CLASS_SCMCTL 	0x0f
#define CLASS_ENCRY 	0x10
#define CLASS_SIGPROC 	0x11
#define CLASS_PROCSPD 	0x12
#define CLASS_NEACC 	0x13
#define CLASS_FPU 	0x40
#define CLASS_NOCLASS 	0xff

#define PCI_IO_MASK 	(~1ul)


#endif

